package com.pengcheng.hngateway.adapter;

import com.pengcheng.hngateway.util.Common;
import com.pengcheng.hngateway.util.SpringUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import io.netty.util.internal.StringUtil;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
public class BootNettyChannelInboundHandlerAdapter  extends ChannelInboundHandlerAdapter {
    public Common common;

    private RabbitTemplate rabbitTemplate;

    public BootNettyChannelInboundHandlerAdapter(Common common, RabbitTemplate rabbitTemplate) {
        this.common = common;
        this.rabbitTemplate = rabbitTemplate;
    }

    public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);



    private static BootNettyChannelInboundHandlerAdapter nettyServerHandler;
    @PostConstruct
    public void init() {
        nettyServerHandler = this;
    }
    /**
     * 从客户端收到新的数据时，这个方法会在收到消息时被调用
     *
     * @param ctx
     * @param msg
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception, IOException {
        try{
            if (msg == null) {
//                log.error("======加载客户端报文为空======【" + ctx.channel().id() + "】" + " :" + msg);
            }
            else {
//                log.info("======加载客户端报文======【" + ctx.channel().id() + "】" + " :" + msg);
                //回应客户端
//                ctx.write(ctx.channel().id()+"服务端已成功接收数据！");
                byte[] message=(byte[])msg;
//                log.info("channelread:"+common.byte2hex(message));
                Map<String,Object> map=new HashMap<>();
                map.put("type",2);
                map.put("channel_id",ctx.channel().id().toString());
                map.put("msg",common.byte2hex(message));
                rabbitTemplate.convertAndSend("hnww.msg",map);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 从客户端收到新的数据、读取完成时调用
     *
     * @param ctx
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws IOException {
//        log.info("channelReadComplete");
        ctx.flush();
    }

    /**
     * 当出现 Throwable 对象才会被调用，即当 Netty 由于 IO 错误或者处理器在处理事件时抛出的异常时
     *
     * @param ctx
     * @param cause
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws IOException {
//        log.info("exceptionCaught");
        cause.printStackTrace();
        ctx.close();//抛出异常，断开与客户端的连接
        remove_handle(ctx.channel());
        Map<String,Object> map=new HashMap<>();
        map.put("type",3);
        map.put("channel_id",ctx.channel().id().toString());
        rabbitTemplate.convertAndSend("hnww.logout",map);
    }

    private void remove_handle(Channel ctx)
    {
//        log.info("remove_handler:"+ctx.id());
        channelGroup.remove(ctx);
    }

    /**
     * 客户端与服务端第一次建立连接时 执行
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception, IOException {
        super.channelActive(ctx);
        ctx.channel().read();
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = insocket.getAddress().getHostAddress();
        //此处不能使用ctx.close()，否则客户端始终无法与服务端建立连接
//        log.info("channelActive:"+clientIp+ctx.name());
        channelGroup.add(ctx.channel());
//        log.info("list_handle.length:"+channelGroup.size());
        Map<String,Object> map=new HashMap<>();
        map.put("type",1);
        map.put("channel_id",ctx.channel().id().toString());
        rabbitTemplate.convertAndSend("hnww.reg",map);
    }

    /**
     * 客户端与服务端 断连时 执行
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception, IOException {
        super.channelInactive(ctx);
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = insocket.getAddress().getHostAddress();
        ctx.close(); //断开连接时，必须关闭，否则造成资源浪费，并发量很大情况下可能造成宕机
        remove_handle(ctx.channel());
//        log.info("channelInactive:"+clientIp);
        Map<String,Object> map=new HashMap<>();
        map.put("type",3);
        map.put("channel_id",ctx.channel().id().toString());
        rabbitTemplate.convertAndSend("hnww.logout",map);
    }

    /**
     * 服务端当read超时, 会调用这个方法
     *
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception, IOException {
        super.userEventTriggered(ctx, evt);
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = insocket.getAddress().getHostAddress();
        if(true)
        {
            Map<String,Object> map=new HashMap<>();
            map.put("type",1);
            map.put("channel_id",ctx.channel().id().toString());
            rabbitTemplate.convertAndSend("hnww.timeout",map);
        }
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception{
//        log.info("channelRegistered");
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception{
        //当一个客户端断开连接或一个服务器完成其服务并关闭连接时
//        log.info("channelUnregistered");
    }
    /**
     * 流量控制是一种拥塞控制机制，
     * 用于防止发送方过多地发送数据，从而导致接收方过载。
     * 当通道变得不可写时，这可能意味着接收方的缓冲区已满，
     * 因此发送方需要停止发送数据，等待通道变得可写时再继续发送
     * @throws Exception
     */
    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception{
        // 通道变得可写，可以继续发送数据
//        log.info("Channel is writable, resuming data transmission.");
    }
    /**
     * 广播数据十六进制,每两个字符为一组，
     *如：09 57 79 30 30 30 30 30 30 30 30 30 30 30 41 30 30 35 30 30
     * 再转为对应ASCII码,即可得到明文的uuid
     * @param uuid
     */
    public String hexToASCII(String uuid) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < uuid.length(); i += 2) {
            String hex = uuid.substring(i, i + 2);
            int decimal = Integer.parseInt(hex, 16);
            char asciiChar = (char) decimal;
            sb.append(asciiChar);
        }
        String result = sb.toString();
        return result;
    }
    /**
     * 将时间戳转换为yyyy-MM-dd HH:mm:ss格式的日期字符串。
     * @param timestamp 时间戳（以毫秒为单位）
     * @return 格式化后的日期字符串
     */
    public String timestampToDate(long timestamp) {
        Instant instant = Instant.ofEpochSecond(timestamp); // 将时间戳转换为Instant对象
        LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); // 将Instant对象转换为本地日期时间对象
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); // 定义日期格式
        // 将日期时间对象格式化为字符串
        String time = dateTime.format(formatter);
        return time;
    }
    /**
     * 将LocalDateTime转换为yyyy-MM-dd HH:mm:ss格式的日期字符串。
     * @return 格式化后的日期字符串
     */
    public String LocalDateTimeToStr() {
        // 获取当前日期时间
        LocalDateTime now = LocalDateTime.now();
        // 定义日期时间的格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 将LocalDateTime格式化为字符串
        String formattedDateTime = now.format(formatter);
        return formattedDateTime;
    }

    @RabbitListener(queues="hnww.respon",containerFactory="rabbitListenerContainerFactory")
    public void receive_respon(Map<String,Object> msg)
    {
//        log.info("receive_respon:"+msg.toString());
        String channel_id=msg.get("channel_id").toString();
        String hexdata=msg.get("msg").toString();
        byte[] data=common.hex2byte(hexdata);
        int index=-1;
//        log.info("now_list_handler.length:"+channelGroup.size());
        channelGroup.forEach(channel -> {
//            log.info(channel.id().toString());
            if(channel.id().toString().equals(channel_id))
            {
//                log.info("find_channel_by_id:"+channel_id);
                ByteBuf bb = Unpooled.buffer(data.length);
                bb.writeBytes(data);
                channel.writeAndFlush(bb);
            }
        });
    }
    @RabbitListener(queues="hnww.kickout",containerFactory="rabbitListenerContainerFactory")
    public void receive_kickout(Map<String,Object> msg)
    {
//        log.info("receive_kickout:"+msg.toString());
        if(msg.get("channel_id")!=null)
        {
            String channel_id=msg.get("channel_id").toString();
            channelGroup.forEach(channel -> {
                if(channel.id().toString().equals(channel_id))
                {
                    channel.close();
                    remove_handle(channel);
                }
            });
        }
    }

}
